package com.flute.haflute.tools;

import static java.util.concurrent.TimeUnit.SECONDS;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.flute.haflute.common.ClusterContext;
import com.flute.haflute.jobbox.common.CloudContext;
import com.flute.haflute.monitor.StatusMessage;
import com.flute.haflute.monitor.UniversalMonitorMsg;

public class PlaceOnFileService {

	private static Logger logger = LoggerFactory
			.getLogger(PlaceOnFileService.class);

	String osName = null;
	static String SEP = File.separator;

	public static PlaceOnFileService placeOnFileSvr;
	static String DIR = CloudContext.getRootDir() + "bakfile";
	final static String bakFileName = "reportInfoBak.txt";
	final static String bakFileNamePrefix = "reportInfoBak_";
	final static String bakFile = DIR + SEP + bakFileName;
	AtomicInteger atomicInt = new AtomicInteger();

	final ScheduledExecutorService scheduler = Executors
			.newScheduledThreadPool(1);

	final Runnable bakSerivce = new Runnable() {
		public void run() {
			try {
				File file = new File(bakFile);
				FileInputStream fis = new FileInputStream(file);
				double filesize = (double) (fis.available() / 1024.0);
				int contextFileSize = ClusterContext.getFileSize();
				if (filesize > contextFileSize) {
					createNewFile(file, -1);
				}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	};

	public static PlaceOnFileService getInstance() {
		try {
			checkDir();
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (null == placeOnFileSvr) {
			placeOnFileSvr = new PlaceOnFileService();
		}
		return placeOnFileSvr;
	}

	PlaceOnFileService() {
		// 1秒钟后运行，并每隔2秒运行一次
		scheduler.scheduleAtFixedRate(bakSerivce, 1, 10, SECONDS);

	}

	private static void checkDir() throws Exception {

		File wayfile = new File(DIR);
		if (!wayfile.exists()) {
			wayfile.mkdirs();
		}
		File file = new File(bakFile);
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		wayfile = null;
		file = null;
	}

	public synchronized void save(String key, Object obj) {
		if (obj instanceof StatusMessage) {
			StatusMessage statusMsg = (StatusMessage) obj;
			placeOnFile(key, statusMsg);
		}
	}

	public void save(ConcurrentMap<String, StatusMessage> map) {
		Iterator<String> it = map.keySet().iterator();
		if (it != null) {
			while (it.hasNext()) {
				String key = it.next();
				save(key, map.get(key));
			}
		}

	}

	private void placeOnFile(String key, StatusMessage statusMsg) {
		String moudle = key.split("\\^")[0];
		String ip = moudle.split("-")[0];
		StringBuffer strbuf = new StringBuffer();
		if (statusMsg.topic != null && statusMsg.topic.indexOf("@") != -1) {
			statusMsg.topic = statusMsg.topic.replace("@", ".");
		}
		if (statusMsg.content != null && statusMsg.content.indexOf("@") != -1) {
			statusMsg.content = statusMsg.content.replace("@", ".");
		}
		if (statusMsg.explanation != null
				&& statusMsg.explanation.indexOf("@") != -1) {
			statusMsg.explanation = statusMsg.explanation.replace("@", ".");
		}
		strbuf.append("ip#")
				.append(ip)
				.append("@")
				.append(" moudle#")
				.append(moudle)
				.append("@")
				.append(" topic#")
				.append(statusMsg.topic)
				.append("@")
				.append(" content#")
				.append(statusMsg.content)
				.append("@")
				.append(" explanation#")
				.append(statusMsg.explanation == null ? "-"
						: statusMsg.explanation).append("@")
				.append(" reportDate#").append(statusMsg.reportDate)
				.append(System.getProperty("line.separator"));
		WriteInText(strbuf.toString());
	}

	private void WriteInText(String fileText) {
		FileLock flock = null;
		FileOutputStream out = null;
		try {
			File file = new File(bakFile);
			out = new FileOutputStream(file, true);
			FileChannel filechannel = out.getChannel();
			flock = filechannel.tryLock();
			if (flock != null && flock.isValid()) {

				out.write(fileText.getBytes("utf-8"));
				// 释放文件锁
				flock.release();
				filechannel.close();
				out.close();
				out = null;
				file = null;
			} else {
				Thread.sleep(2000);
				WriteInText(fileText);
			}
		} catch (Exception e) {
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
			WriteInText(fileText);
		} finally {
			try {
				if (flock != null && flock.isValid()) {
					// 释放文件锁
					flock.release();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private void createNewFile(File file, int sequence) throws IOException {
		try {

			String today = getCurrentDate();

			String filename = bakFileNamePrefix + today + ".txt";
			if (sequence >= 0) {
				filename = bakFileNamePrefix + today + "_"
						+ String.valueOf(sequence) + ".txt";
			}
			String fileDir = DIR + SEP + filename;
			File newfile = new File(fileDir);
			if (!newfile.exists()) {
				newfile.createNewFile();
			} else {
				this.createNewFile(file, atomicInt.getAndAdd(1));
			}
			BufferedReader br = new BufferedReader(new FileReader(file));
			BufferedWriter bw = new BufferedWriter(new FileWriter(newfile));
			String str = "";
			while (br.ready()) {
				str = br.readLine();
				bw.write(str);
				bw.newLine();
			}
			bw.close();
			br.close();

			deleteFile(file);
			checkDir();

		} catch (Exception e) {
			e.printStackTrace();
			try {
				Thread.sleep(3000);
				createNewFile(file, -1);
			} catch (InterruptedException e1) {
				logger.error("file create error:" + e);
			}
		}
	}

	private void deleteFile(File file) {
		boolean isDeled = file.delete();
		if (!isDeled) {
			FileOutputStream out;
			try {
				out = new FileOutputStream(file);
				out.write(new String("").getBytes());
				out.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	}

	private UniversalMonitorMsg transFormStatusMessage(StringBuffer sBuffer) {
		UniversalMonitorMsg univerMsg = new UniversalMonitorMsg();
		StatusMessage statusMsg = new StatusMessage();
		String args[] = sBuffer.toString().split("@");
		for (String str : args) {
			String arrys[] = str.split("#");
			if (arrys[0].trim().equals("ip")) {
				univerMsg.setIp(arrys[1]);
			} else if (arrys[0].trim().equals("moudle")) {
				univerMsg.setMoudle(arrys[1]);
			} else if (arrys[0].trim().equals("topic")) {
				statusMsg.topic = arrys[1];
			} else if (arrys[0].trim().equals("content")) {
				statusMsg.content = arrys[1];
			} else if (arrys[0].trim().equals("explanation")) {
				statusMsg.explanation = arrys[1];
			} else if (arrys[0].trim().equals("reportDate")) {
				statusMsg.reportDate = arrys[1];
			}
		}
		univerMsg.setStatusMsg(statusMsg);
		return univerMsg;
	}

	private String getCurrentDate() {
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		return sdf.format(calendar.getTime());
	}

	/**
	 * 
	 * @param day
	 *            "yyyyMMdd"
	 * @return
	 */
	public List<UniversalMonitorMsg> readText(String day) {
		List<UniversalMonitorMsg> list = new ArrayList<UniversalMonitorMsg>();
		String filename = bakFileName;
		if (day != null) {
			filename = bakFileNamePrefix + day + ".txt";
		}
		String filePath = DIR + SEP + filename;
		File file = null;
		InputStreamReader read = null;
		BufferedReader reader = null;

		try {
			file = new File(filePath);
			if (!file.exists()) {
				logger.error(" file not found -> " + filePath);
				return null;
			}
			read = new InputStreamReader(new FileInputStream(file), "UTF-8");
			reader = new BufferedReader(read);

			// 从文件读取一行字符串
			String Line = reader.readLine();

			// 判断读取到的字符串是否不为空
			StringBuffer sBuffer = new StringBuffer();
			while (Line != null) {
				sBuffer.append(Line);
				UniversalMonitorMsg univerMsg = transFormStatusMessage(sBuffer);
				list.add(univerMsg);
				Line = reader.readLine();
			}
		} catch (IOException e) {
			logger.error("readText error " + e);
		} finally {

			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			if (read != null) {
				try {
					read.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			file = null;
		}
		return list;
	}
}
